package engine;

import java.util.List;
import java.util.Map;
import java.util.Vector;

import javax.servlet.ServletContext;

import dao.DaoPassageTrainTheorique;
import externaldata.gare.Gare;
import externaldata.passageTrainReel.PackPassageTrainReel;
import externaldata.passageTrainReel.PassageTrainReel;
import externaldata.passageTrainReel.PassageTrainReelHelper;
import externaldata.passageTrainTheorique.PassageTrainTheorique;
import externaldata.passageTrainTheorique.PassageTrainTheoriqueLive;

/**
 * Thread chargé de récupérer les horaires réels des trains d'une station
 * et de les comparer avec ceux théoriques stockés en BDD.
 * Si besoin, ce thread devra mettre à jour les paris faits par les utilisateurs.
 */
public class StationTask implements Runnable {
	
	private Gare gare;
	private PackPassageTrainReel trainsActuels;
	private ServletContext context;
	
	public StationTask(Gare gare, ServletContext context) {
		this.gare = gare;
		this.context = context;
	}

	
	@Override
	public void run() {
		
		trainsActuels = null;
		
		try {
			trainsActuels = PassageTrainReelHelper.getDataFromAPI(gare.getUic());
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		if (trainsActuels != null) {			
			
			@SuppressWarnings("unchecked")
			Map<String, List<PassageTrainTheoriqueLive>> parisDansContexte = 
				((Map<String, List<PassageTrainTheoriqueLive>>) context.getAttribute("paris_disponibles"));
			
			List<PassageTrainTheoriqueLive> tmpNewListeParisDispos = 
					new Vector<PassageTrainTheoriqueLive>(parisDansContexte.get(gare.getDua()));
			
			// Mise à jour des PTTL en fonction des données récupérées dans l'API temps réel
			for (PassageTrainReel passageReel : trainsActuels.passagesList) {
				
				String numTrain = passageReel.getNumeroTrain();
				
				PassageTrainTheorique passageTheoriqueCorrespondant = 
						DaoPassageTrainTheorique.getOne(numTrain, gare.getDua(), passageReel.getArriveeGare());
				
				// Test du numTrain -1 (dépend du sens du train), voir explication sur :
				// http://data.sncf.com/forum/le-programme-sncf-open-data/topics/liste-gare-desservis-par-un-train
				if (passageTheoriqueCorrespondant == null) {
					numTrain = String.format("%06d", (Integer.parseInt(numTrain) - 1));
					passageTheoriqueCorrespondant = DaoPassageTrainTheorique.getOne(numTrain, gare.getDua(), passageReel.getArriveeGare());
				}

				
				if (passageTheoriqueCorrespondant != null) {
					
					PassageTrainTheoriqueLive passageTheoriqueCorrespondantLive = null;
					
					
					// Si le PTT est déjà dans la liste des paris dispos
					for (PassageTrainTheoriqueLive pttl : tmpNewListeParisDispos) {
						if (pttl.equals(passageTheoriqueCorrespondant)) {
							passageTheoriqueCorrespondantLive = pttl;
							break;
						}
					}
					
					// Si le PTT est nouveau et doit être ajouté à la liste des paris dispos
					if (passageTheoriqueCorrespondantLive == null) {
						
						passageTheoriqueCorrespondantLive = new PassageTrainTheoriqueLive(passageTheoriqueCorrespondant);
						tmpNewListeParisDispos.add(passageTheoriqueCorrespondantLive);
					}
					
					
					
					// Maj des données "live"
					passageTheoriqueCorrespondantLive.setArriveeReelleEnGare(passageReel.getArriveeGare());
					
					
					if ((passageTheoriqueCorrespondantLive.getArriveeReelleEnGare().getTime() 
							- trainsActuels.dateHeureRequeteHttp.getTime()) >= 15*60*1000) {
						passageTheoriqueCorrespondantLive.setPourraitEtreAnnule(true);
					}
					else {
						passageTheoriqueCorrespondantLive.setPourraitEtreAnnule(false);
					}
					
					// Maj des données "PTT"
					passageTheoriqueCorrespondantLive.setDestinationUic(passageReel.getDestinationUic());
					DaoPassageTrainTheorique.updateOne(passageTheoriqueCorrespondantLive);
				}
			}
			
			List<PassageTrainTheoriqueLive> newListeParisDispos = 
					new Vector<PassageTrainTheoriqueLive>(tmpNewListeParisDispos);
			
			// Parcourt de la liste des paris dispos qui vient d'être mise à jour
			for (PassageTrainTheoriqueLive pttl : tmpNewListeParisDispos) {
				
				// Pari encore possible sur ce train ?
				if ((pttl.getArriveeReelleEnGare().getTime() - trainsActuels.dateHeureRequeteHttp.getTime()) >= 10*60*1000) {
					pttl.setPariAutorise(true);
				}
				else {
					pttl.setPariAutorise(false);
				}
				
				// Train passe en gare selon les dernières infos reçues de l'API temps réel
				if (pttl.getArriveeReelleEnGare().getTime() == trainsActuels.dateHeureRequeteHttp.getTime()) {
					
					if (pttl.getPourraitEtreAnnule()) {
						// Train annulé (ou retard incalculable car données trop anciennes)
						DaoPassageTrainTheorique.deleteOne(pttl);
					}
					else {
						// Train bien en gare
						long retardSecondes = (pttl.getArriveeReelleEnGare().getTime() 
								- pttl.getArriveeTheorique().getTime()) / 1000;
						
						DaoPassageTrainTheorique.validerTrainEnGare(pttl, (int)retardSecondes / 60);
					}
					
					newListeParisDispos.remove(pttl);
				}
			}
			
			// On valide les défis qui portent sur les éventuels paris des trains qui sont passés en gare
			DaoPassageTrainTheorique.validerDefis();
						
			
			/*
			for (PassageTrainTheoriqueLive pttl : newListeParisDispos) {
				System.out.println("Pari possible : ");
				System.out.println("\tNum train : " + pttl.getNumeroTrain());
				System.out.println("\tNom train : " + pttl.getNomTrain());
				System.out.println("\tRéseau train : " + pttl.getReseauTrain());
				System.out.println("\tGare de passage : " + pttl.getGareDua());
				System.out.println("\tHeure de passage théorique : " + pttl.getArriveeTheorique().toString());
				System.out.println("\tHeure de passage réelle prévue : " + pttl.getArriveeReelleEnGare().toString());
				System.out.println("\tPari encore autorisé dessus : " + pttl.getPariAutorise());
				System.out.println("\tDonnées potentiellement périmées (plus de 15 minutes) : " + pttl.getPourraitEtreAnnule());
			}
			*/
			
			// On met la nouvelle liste de paris dispos dans le contexte
			parisDansContexte.put(gare.getDua(), newListeParisDispos);
			
			System.out.println("Fin d'update train temps réel.");
		}
	}

}
